# install.packages("tidyverse");
# install.packages("rgdal");
library(tidyverse)
require("maps")
library(geosphere)
library(stringr)
library(rgdal)
library(caret)
library(lubridate)
if (!require(ggmap)) { install.packages('ggmap'); require(ggmap) }
library(ggmap)
path.to.csv <- '../Milestone 2/Seattle_Police_Department_911_Incident_Response_Oct17.csv'
spd.911 <- read.csv(path.to.csv, TRUE)
spd.911$clearance_date_ts = as.POSIXct(strptime(spd.911$Event.Clearance.Date, "%m/%d/%Y %I:%M:%S %p"))
spd.911$clearance_date_date = as.Date(spd.911$clearance_date_ts)
View(spd.911)
# path to the FOLDER with the .shp file in it. the second param is the name of the .shp file
# seattle <- readOGR(dsn = path.expand("~/documents/INFO370/project-teamname-v2/maps-api-test"), layer = "Seattle_City_Limits")
# usa <- map_data("state")
# data <- merge(usa, spd.911)
# Red Square coordinates
here_long <- -122.3095
here_lat <- 47.6560
seattle = get_map(location = c(here_long, here_lat), zoom = 13, maptype = 'roadmap')
Map from URL : http://maps.googleapis.com/maps/api/staticmap?center=47.656,-122.3095&zoom=13&size=640x640&scale=2&maptype=roadmap&language=en-EN&sensor=false

freq_by_desc <- table(droplevels(data$Event.Clearance.Description))
# View(freq_by_desc)
ggplot(as.data.frame(freq_by_desc),
aes(x = Var1, y = Freq)) +
geom_bar(stat = 'identity') +# create bar plot
coord_flip()

#Traffic related calls, suspicious circumstances, and disturbances are the the most significant threats to pedestrations
ggmap(seattle) +
geom_point(data = data, aes(x = Longitude, y = Latitude, group = Event.Clearance.Description, color = Event.Clearance.Description), alpha = 0.5) +
facet_wrap(~ Event.Clearance.Description) +
theme(axis.ticks = element_blank(),
axis.text.x = element_blank(),
axis.text.y = element_blank(),
legend.position = "none"
)

# selecting just ID and location data
df_loc <- data %>% dplyr::select(CAD.CDW.ID, Longitude, Latitude)
# figuring out number of clusters
wss <- c()
# clusters 1 to 15
for (i in 1:15) {
wss[i] <- sum(kmeans(df_loc, centers=i)$withinss)
}
plot(1:15, wss, type="b", xlab="Number of Clusters",
ylab="Within groups sum of squares")

# fitting model
fit <- kmeans(df_loc, 10)
fit$centers # look at cluster sizes and means. want clusters to be about equal size
CAD.CDW.ID Longitude Latitude
1 2110534 -122.3090 47.65473
2 2108019 -122.3145 47.65467
3 2114454 -122.3135 47.66288
4 2115894 -122.3117 47.66063
5 2117445 -122.3115 47.66015
6 2105779 -122.3122 47.65821
7 2119756 -122.3128 47.65627
8 2122787 -122.3178 47.66599
9 2112589 -122.3124 47.66454
10 2124681 -122.3089 47.65948
fit$cluster
[1] 6 6 6 6 6 6 6 6 6 2 2 2 2 2 2 1 1 1 1 1 1 1 9 9 9 9 9 9 9 9 9 9 3 3
[35] 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 7 7 7 7 7 7 7 7
[69] 7 7 7 7 7 8 8 8 8 8 8 8 8 8 8 10 10 10 10 10 10 10 10 10
cluster.size <- data.frame(1:10, fit$size)
cluster.size
ggplot(data = cluster.size, aes(x = X1.10, y = fit.size)) +
geom_bar(stat = 'identity')

ggplot()

ggmap(seattle) +
geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
aggregate(df_loc, by=list(fit$cluster), FUN=mean)
df_loc
# adding data back into dataframe
# df_loc <- df_loc %>% mutate(cluster = fit$cluster)
data$cluster <- fit$cluster
# View(data)
# timestamp -> year month day hour minute
# sector -> to factor (there are 17 sectors)
# beat -> to factor (there are 3 beats per sector)
# clean the data a bit more
data$event_clearance_ts = as.POSIXct(strptime(data$Event.Clearance.Date, "%m/%d/%Y %I:%M:%S %p"))
data$event_clearance_date = as.Date(data$event_clearance_ts)
data$event_clearance_month = month(ymd_hms(as.character(data$event_clearance_ts)))
data$event_clearance_day = weekdays(data$event_clearance_date)
data$event_clearance_hr = hour(ymd_hms(as.character(data$event_clearance_ts)))
data$event_clearance_mn = minute(ymd_hms(as.character(data$event_clearance_ts)))
data$Initial.Type.Group = factor(data$Initial.Type.Group)
data$Event.Clearance.Group = factor(data$Event.Clearance.Group)
data$Zone.Beat = factor(data$Zone.Beat)
data$District.Sector = factor(data$District.Sector)
data$event_clearance_day = factor(data$event_clearance_day)
data
col.names <- paste(c(
"Event.Clearance.Code"
, "cluster"
, "Census.Tract"
, "event_clearance_day"
, "Event.Clearance.Group"
, "Event.Clearance.SubGroup"
, "District.Sector"
, "Zone.Beat"
#, "event_clearance_ts"
# ,"Incident.Location"
, "event_clearance_hr"
, "event_clearance_mn"
, "event_clearance_month"
, "Hundred.Block.Location"
), collapse="|")
cols <- grep(col.names, colnames(data))
cols
[1] 4 6 7 9 10 11 12 23 26 27 28 29
# corr_matrix <- cor(data[,cols]) # correlations between all predictor vars
# corr_matrix
# cutoff <- 0.5 # should be higher in practice
# highly_corr <- findCorrelation(corr_matrix, cutoff=cutoff)
# print(colnames(spd.911)[highly_corr]) # age is highly correalted with pregnant
train.data <- select(data, cols)
train.data
# data <- data %>% droplevels()
# grep("Hundred.Block.Location", colnames(train.data), invert = T)
predictors <- grep("Hundred.Block.Location", colnames(train.data), invert = T)
outcome <- grep("Hundred.Block.Location", colnames(train.data))
# train.data[,predictors]
frame <- data.frame(train.data[,predictors])
frame
out.factor <- train.data$Hundred.Block.Location
as.vector(out.factor)
[1] "43XX BLOCK OF 15 AV NE" "24XX BLOCK OF E LOUISA ST"
[3] "48XX BLOCK OF SAND POINT WY NE" "42XX BLOCK OF UNIVERSITY WY NE"
[5] "21XX BLOCK OF N NORTHLAKE WY" "14XX BLOCK OF NE 43 ST"
[7] "14XX BLOCK OF NE 43 ST" "17XX BLOCK OF N 45 ST"
[9] "NE 54 ST / 21 AV NE" "29XX BLOCK OF FAIRVIEW AV E"
[11] "SAND POINT WY NE / 40 AV NE" "55XX BLOCK OF 12 AV NE"
[13] "NE 43 ST / UNIVERSITY WY NE" "E ROANOKE ST / I5 NB"
[15] "E HAMLIN ST / EASTLAKE AV E" "23XX BLOCK OF 24 AV E"
[17] "50XX BLOCK OF UNIVERSITY WY NE" "E MONTLAKE PL E / E LAKE WASHINGTON BV"
[19] "14XX BLOCK OF NE 43 ST" "16XX BLOCK OF INTERLAKEN PL E"
[21] "8XX BLOCK OF NE 66 ST" "NE 47 ST / 17 AV NE"
[23] "45XX BLOCK OF 16 AV NE" "16XX BLOCK OF NE 50 ST"
[25] "45XX BLOCK OF UNIVERSITY WY NE" "47XX BLOCK OF UNIVERSITY WY NE"
[27] "NE 52 ST / ROOSEVELT WY NE" "NE 50 ST / 9 AV NE"
[29] "45XX BLOCK OF 25 AV NE" "61XX BLOCK OF BROOKLYN AV NE"
[31] "47XX BLOCK OF UNIVERSITY WY NE" "45XX BLOCK OF UNIVERSITY WY NE"
[33] "15 AV NE / NE 55 ST" "NE 45 ST / 11 AV NE"
[35] "46XX BLOCK OF 27 AV NE" "2 AV NE / NE 50 ST"
[37] "11 AV NE / NE 42 ST" "50XX BLOCK OF 7 AV NE"
[39] "NE BLAKELEY ST / 25 AV NE" "4213 1 / 2 UNIVERSITY WY NE"
[41] "15 AV NE / NE 42 ST" "NE 47 ST / 9 AV NE"
[43] "NE 45 ST / 5 AV NE" "NE 52 ST / 15 AV NE"
[45] "47XX BLOCK OF 30 AV NE" "UNIVERSITY WY NE / NE 56 ST"
[47] "ROOSEVELT WY NE / NE 45 ST" "50XX BLOCK OF UNIVERSITY WY NE"
[49] "41XX BLOCK OF UNIVERSITY WY NE" "45XX BLOCK OF 15 AV NE"
[51] "27XX BLOCK OF MONTLAKE BV E" "14XX BLOCK OF N 42 ST"
[53] "38XX BLOCK OF 42 AV NE" "42XX BLOCK OF UNIVERSITY WY NE"
[55] "48XX BLOCK OF SAND POINT WY NE" "24XX BLOCK OF E LOUISA ST"
[57] "37XX BLOCK OF CORLISS AV N" "45XX BLOCK OF 18 AV NE"
[59] "ROOSEVELT WY NE / NE 63 ST" "NE 50 ST / 2 AV NE"
[61] "45XX BLOCK OF 25 AV NE" "48XX BLOCK OF SAND POINT WY NE"
[63] "45XX BLOCK OF 9 AV NE" "14XX BLOCK OF N 45 ST"
[65] "15 AV NE / NE 50 ST" "23XX BLOCK OF MINOR AV E"
[67] "24 AV E / E MONTLAKE PL E" "50XX BLOCK OF ROOSEVELT WY NE"
[69] "8XX BLOCK OF NE 42 ST" "40XX BLOCK OF UNIVERSITY WY NE"
[71] "38XX BLOCK OF NE 57 ST" "9XX BLOCK OF E ROANOKE ST"
[73] "23XX BLOCK OF EASTLAKE AV E" "BURKE AV N / N NORTHLAKE WY"
[75] "22XX BLOCK OF NE 51 ST" "52XX BLOCK OF 22 AV NE"
[77] "N 45 ST / BURKE AV N" "LATONA AV NE / NE 58 ST"
[79] "1 AV NE / N 56 ST" "ROOSEVELT WY NE / NE 65 ST"
[81] "43XX BLOCK OF UNIVERSITY WY NE" "65XX BLOCK OF 18 AV NE"
[83] "50XX BLOCK OF 19 AV NE" "EASTLAKE AV E / E BOSTON ST"
[85] "45XX BLOCK OF 12 AV NE" "15 AV NE / NE 50 ST"
[87] "14XX BLOCK OF NE 43 ST" "22 AV E / E MILLER ST"
[89] "50XX BLOCK OF RAVENNA AV NE" "52XX BLOCK OF 15 AV NE"
[91] "55XX BLOCK OF 17 AV NE" "39 AV NE / NE 55 ST"
control <- rfeControl(functions = rfFuncs, method="cv", number=10)
results <- rfe(frame, out.factor, sizes = c(1:13), rfeControl = control) # this will take AWHILE...
Error in { : task 1 failed - "Can't have empty classes in y."
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXB9CiMgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIik7CiMgaW5zdGFsbC5wYWNrYWdlcygicmdkYWwiKTsKbGlicmFyeSh0aWR5dmVyc2UpCnJlcXVpcmUoIm1hcHMiKQpsaWJyYXJ5KGdlb3NwaGVyZSkKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHJnZGFsKQpsaWJyYXJ5KGNhcmV0KQpsaWJyYXJ5KGx1YnJpZGF0ZSkKaWYgKCFyZXF1aXJlKGdnbWFwKSkgeyBpbnN0YWxsLnBhY2thZ2VzKCdnZ21hcCcpOyByZXF1aXJlKGdnbWFwKSB9CmxpYnJhcnkoZ2dtYXApCnBhdGgudG8uY3N2IDwtICcuLi9NaWxlc3RvbmUgMi9TZWF0dGxlX1BvbGljZV9EZXBhcnRtZW50XzkxMV9JbmNpZGVudF9SZXNwb25zZV9PY3QxNy5jc3YnCnNwZC45MTEgPC0gcmVhZC5jc3YocGF0aC50by5jc3YsIFRSVUUpCgpzcGQuOTExJGNsZWFyYW5jZV9kYXRlX3RzID0gYXMuUE9TSVhjdChzdHJwdGltZShzcGQuOTExJEV2ZW50LkNsZWFyYW5jZS5EYXRlLCAiJW0vJWQvJVkgJUk6JU06JVMgJXAiKSkKc3BkLjkxMSRjbGVhcmFuY2VfZGF0ZV9kYXRlID0gYXMuRGF0ZShzcGQuOTExJGNsZWFyYW5jZV9kYXRlX3RzKQpWaWV3KHNwZC45MTEpCgoKCiMgcGF0aCB0byB0aGUgRk9MREVSIHdpdGggdGhlIC5zaHAgZmlsZSBpbiBpdC4gdGhlIHNlY29uZCBwYXJhbSBpcyB0aGUgbmFtZSBvZiB0aGUgLnNocCBmaWxlCiMgc2VhdHRsZSA8LSByZWFkT0dSKGRzbiA9IHBhdGguZXhwYW5kKCJ+L2RvY3VtZW50cy9JTkZPMzcwL3Byb2plY3QtdGVhbW5hbWUtdjIvbWFwcy1hcGktdGVzdCIpLCBsYXllciA9ICJTZWF0dGxlX0NpdHlfTGltaXRzIikKCiMgdXNhIDwtIG1hcF9kYXRhKCJzdGF0ZSIpCiMgZGF0YSA8LSBtZXJnZSh1c2EsIHNwZC45MTEpCiMgUmVkIFNxdWFyZSBjb29yZGluYXRlcwpoZXJlX2xvbmcgPC0gIC0xMjIuMzA5NQpoZXJlX2xhdCA8LSA0Ny42NTYwCgpzZWF0dGxlID0gZ2V0X21hcChsb2NhdGlvbiA9IGMoaGVyZV9sb25nLCBoZXJlX2xhdCksIHpvb20gPSAxMywgbWFwdHlwZSA9ICdyb2FkbWFwJykKCmBgYAoKCmBgYHtyfQoKCnNwZC45MTEgPC0gc3BkLjkxMSAlPiUgCiAgICAgICAgICAgICByb3d3aXNlKCkgJT4lIAogICAgICAgICAgICAgbXV0YXRlKGRpc3Q9ZGlzdFZpbmNlbnR5RWxsaXBzb2lkKGMoTG9uZ2l0dWRlLCBMYXRpdHVkZSksIGMoaGVyZV9sb25nLCBoZXJlX2xhdCkpKSAgICAgICAgICAgICAgCm5yb3coc3BkLjkxMSkKCmRlc2NyaXB0aW9ucyA8LSBjKCJTVFJPTkcgQVJNIFJPQkJFUlkiLCAiUEVSU09OIFdJVEggQSBXRUFQT04gKE5PVCBHVU4pIiwgIkhBWkFSRFMiLCAiSEFSQVNTTUVOVCwgVEhSRUFUUyIsICJGSUdIVCBESVNUVVJCQU5DRSIsICJDUklTSVMgQ09NUExBSU5UIC0gR0VORVJBTCIsICJBUk1FRCBST0JCRVJZIikKCiMgUmVtb3ZlcyBTcGVjaWZpY2FsbHkgSGFyYXNzbWVudCBieSBUZWxlcGhvbmUgYW5kIFdyaXRpbmcsIGFzIHdlbGwgYXMgb3RoZXIgbm9uLXNjYXJ5IGNyaW1lcwpkYXRhLnBlZCA8LSBzcGQuOTExICU+JSBmaWx0ZXIoc3RyX2RldGVjdChFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24sIHBhc3RlKGRlc2NyaXB0aW9ucywgY29sbGFwc2U9InwiKSkpICU+JSBmaWx0ZXIoIXN0cl9kZXRlY3QoRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uLCAiSEFSQVNTTUVOVCwgVEhSRUFUUyAtIEJZIFRFTEVQSE9ORSwgV1JJVElORyIpKQojIGRhdGEucGVkIDwtIGRhdGEubm93Cm5yb3coZGF0YS5wZWQpCgojIGRhdGEubm93IDwtIGRhdGEucGVkICU+JSBmaWx0ZXIoY2xlYXJhbmNlX2RhdGVfdHMgPCAnMjAxNy0xMC0zMSAwMDowMDowMCcpCm5yb3coZGF0YS5ub3cpCiAgICAgICAgICAgICAgICAgIApkYXRhLmhlcmUgPC0gZGF0YS5ub3cgJT4lIGZpbHRlcihkaXN0IDwgMjYwMCkKCmRhdGEgPC0gcmVhZC5jc3YoJ1llYXJTRUFQRC5jc3YnLCBoZWFkZXIgPSBUUlVFKQpucm93KGRhdGEpCiMgVmlldyhkYXRhKQoKZ2dtYXAoc2VhdHRsZSkgKwogICBnZW9tX3BvaW50KGRhdGEgPSBkYXRhLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgY29sb3VyID0gInJlZCIsIGFscGhhID0gMC43NSkKICAjY29vcmRfbWFwKCkKCmBgYAoKYGBge3J9CmZyZXFfYnlfZGVzYyA8LSB0YWJsZShkcm9wbGV2ZWxzKGRhdGEkRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKSkKIyBWaWV3KGZyZXFfYnlfZGVzYykKCmdncGxvdChhcy5kYXRhLmZyYW1lKGZyZXFfYnlfZGVzYyksIAogICAgICAgYWVzKHggPSBWYXIxLCB5ID0gRnJlcSkpICsKICAgICAgIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknKSArIyBjcmVhdGUgYmFyIHBsb3QKICAgIGNvb3JkX2ZsaXAoKQoKI1RyYWZmaWMgcmVsYXRlZCBjYWxscywgc3VzcGljaW91cyBjaXJjdW1zdGFuY2VzLCBhbmQgZGlzdHVyYmFuY2VzIGFyZSB0aGUgdGhlIG1vc3Qgc2lnbmlmaWNhbnQgdGhyZWF0cyB0byBwZWRlc3RyYXRpb25zCgogICAgICAgIApgYGAKCmBgYHtyfQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZGF0YSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSwgZ3JvdXAgPSBFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24sIGNvbG9yID0gRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKSwgYWxwaGEgPSAwLjUpICsKICBmYWNldF93cmFwKH4gRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKSArCiAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiCiAgICAgICAgKQpgYGAKCmBgYHtyfQojIHNlbGVjdGluZyBqdXN0IElEIGFuZCBsb2NhdGlvbiBkYXRhCmRmX2xvYyA8LSBkYXRhICU+JSBkcGx5cjo6c2VsZWN0KENBRC5DRFcuSUQsIExvbmdpdHVkZSwgTGF0aXR1ZGUpCgojIGZpZ3VyaW5nIG91dCBudW1iZXIgb2YgY2x1c3RlcnMKd3NzIDwtIGMoKQojIGNsdXN0ZXJzIDEgdG8gMTUKZm9yIChpIGluIDE6MTUpIHsKICB3c3NbaV0gPC0gc3VtKGttZWFucyhkZl9sb2MsIGNlbnRlcnM9aSkkd2l0aGluc3MpCn0KcGxvdCgxOjE1LCB3c3MsIHR5cGU9ImIiLCB4bGFiPSJOdW1iZXIgb2YgQ2x1c3RlcnMiLAogIHlsYWI9IldpdGhpbiBncm91cHMgc3VtIG9mIHNxdWFyZXMiKQoKIyBmaXR0aW5nIG1vZGVsCmZpdCA8LSBrbWVhbnMoZGZfbG9jLCAxMCkKZml0JGNlbnRlcnMgIyBsb29rIGF0IGNsdXN0ZXIgc2l6ZXMgYW5kIG1lYW5zLiB3YW50IGNsdXN0ZXJzIHRvIGJlIGFib3V0IGVxdWFsIHNpemUKZml0JGNsdXN0ZXIKY2x1c3Rlci5zaXplIDwtIGRhdGEuZnJhbWUoMToxMCwgZml0JHNpemUpCmNsdXN0ZXIuc2l6ZQoKZ2dwbG90KGRhdGEgPSBjbHVzdGVyLnNpemUsIGFlcyh4ID0gWDEuMTAsIHkgPSBmaXQuc2l6ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykKZ2dwbG90KCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCiMgbG9va2luZyBhdCBjbHVzdGVyIG1lYW5zCmFnZ3JlZ2F0ZShkZl9sb2MsIGJ5PWxpc3QoZml0JGNsdXN0ZXIpLCBGVU49bWVhbikKCmRmX2xvYwoKIyBhZGRpbmcgZGF0YSBiYWNrIGludG8gZGF0YWZyYW1lIAojIGRmX2xvYyA8LSBkZl9sb2MgJT4lIG11dGF0ZShjbHVzdGVyID0gZml0JGNsdXN0ZXIpIApkYXRhJGNsdXN0ZXIgPC0gZml0JGNsdXN0ZXIKCiMgVmlldyhkYXRhKQpgYGAKCmBgYHtyfQojIHRpbWVzdGFtcCAtPiAgeWVhciAgbW9udGggZGF5IGhvdXIgIG1pbnV0ZQojIHNlY3RvciAtPiB0byBmYWN0b3IgKHRoZXJlIGFyZSAxNyBzZWN0b3JzKQojIGJlYXQgLT4gdG8gZmFjdG9yICh0aGVyZSBhcmUgMyBiZWF0cyBwZXIgc2VjdG9yKQoKIyBjbGVhbiB0aGUgZGF0YSBhIGJpdCBtb3JlCmRhdGEkZXZlbnRfY2xlYXJhbmNlX3RzID0gYXMuUE9TSVhjdChzdHJwdGltZShkYXRhJEV2ZW50LkNsZWFyYW5jZS5EYXRlLCAiJW0vJWQvJVkgJUk6JU06JVMgJXAiKSkKZGF0YSRldmVudF9jbGVhcmFuY2VfZGF0ZSA9IGFzLkRhdGUoZGF0YSRldmVudF9jbGVhcmFuY2VfdHMpCmRhdGEkZXZlbnRfY2xlYXJhbmNlX21vbnRoID0gbW9udGgoeW1kX2htcyhhcy5jaGFyYWN0ZXIoZGF0YSRldmVudF9jbGVhcmFuY2VfdHMpKSkKZGF0YSRldmVudF9jbGVhcmFuY2VfZGF5ID0gd2Vla2RheXMoZGF0YSRldmVudF9jbGVhcmFuY2VfZGF0ZSkKZGF0YSRldmVudF9jbGVhcmFuY2VfaHIgPSBob3VyKHltZF9obXMoYXMuY2hhcmFjdGVyKGRhdGEkZXZlbnRfY2xlYXJhbmNlX3RzKSkpCmRhdGEkZXZlbnRfY2xlYXJhbmNlX21uID0gbWludXRlKHltZF9obXMoYXMuY2hhcmFjdGVyKGRhdGEkZXZlbnRfY2xlYXJhbmNlX3RzKSkpCmRhdGEkSW5pdGlhbC5UeXBlLkdyb3VwID0gZmFjdG9yKGRhdGEkSW5pdGlhbC5UeXBlLkdyb3VwKQpkYXRhJEV2ZW50LkNsZWFyYW5jZS5Hcm91cCA9IGZhY3RvcihkYXRhJEV2ZW50LkNsZWFyYW5jZS5Hcm91cCkKZGF0YSRab25lLkJlYXQgPSBmYWN0b3IoZGF0YSRab25lLkJlYXQpCmRhdGEkRGlzdHJpY3QuU2VjdG9yID0gZmFjdG9yKGRhdGEkRGlzdHJpY3QuU2VjdG9yKQpkYXRhJGV2ZW50X2NsZWFyYW5jZV9kYXkgPSBmYWN0b3IoZGF0YSRldmVudF9jbGVhcmFuY2VfZGF5KQpkYXRhCgpjb2wubmFtZXMgPC0gcGFzdGUoYygKICAiRXZlbnQuQ2xlYXJhbmNlLkNvZGUiCiAgLCAiY2x1c3RlciIKICAsICJDZW5zdXMuVHJhY3QiCiAgLCAiZXZlbnRfY2xlYXJhbmNlX2RheSIKICAsICJFdmVudC5DbGVhcmFuY2UuR3JvdXAiCiAgLCAiRXZlbnQuQ2xlYXJhbmNlLlN1Ykdyb3VwIgogICwgIkRpc3RyaWN0LlNlY3RvciIKICAsICJab25lLkJlYXQiCiAgIywgImV2ZW50X2NsZWFyYW5jZV90cyIKICAjICwiSW5jaWRlbnQuTG9jYXRpb24iCiAgLCAiZXZlbnRfY2xlYXJhbmNlX2hyIgogICwgImV2ZW50X2NsZWFyYW5jZV9tbiIKICAsICJldmVudF9jbGVhcmFuY2VfbW9udGgiIAogICwgIkh1bmRyZWQuQmxvY2suTG9jYXRpb24iCiAgKSwgY29sbGFwc2U9InwiKQpjb2xzIDwtIGdyZXAoY29sLm5hbWVzLCBjb2xuYW1lcyhkYXRhKSkKY29scwojIGNvcnJfbWF0cml4IDwtIGNvcihkYXRhWyxjb2xzXSkgIyBjb3JyZWxhdGlvbnMgYmV0d2VlbiBhbGwgcHJlZGljdG9yIHZhcnMKIyBjb3JyX21hdHJpeAoKIyBjdXRvZmYgPC0gMC41ICMgc2hvdWxkIGJlIGhpZ2hlciBpbiBwcmFjdGljZQoKIyBoaWdobHlfY29yciA8LSBmaW5kQ29ycmVsYXRpb24oY29ycl9tYXRyaXgsIGN1dG9mZj1jdXRvZmYpCiMgcHJpbnQoY29sbmFtZXMoc3BkLjkxMSlbaGlnaGx5X2NvcnJdKSAjIGFnZSBpcyBoaWdobHkgY29ycmVhbHRlZCB3aXRoIHByZWduYW50Cgp0cmFpbi5kYXRhIDwtIHNlbGVjdChkYXRhLCBjb2xzKQp0cmFpbi5kYXRhCiMgZGF0YSA8LSBkYXRhICU+JSBkcm9wbGV2ZWxzKCkKCiMgZ3JlcCgiSHVuZHJlZC5CbG9jay5Mb2NhdGlvbiIsIGNvbG5hbWVzKHRyYWluLmRhdGEpLCBpbnZlcnQgPSBUKQoKcHJlZGljdG9ycyA8LSBncmVwKCJIdW5kcmVkLkJsb2NrLkxvY2F0aW9uIiwgY29sbmFtZXModHJhaW4uZGF0YSksIGludmVydCA9IFQpCm91dGNvbWUgPC0gZ3JlcCgiSHVuZHJlZC5CbG9jay5Mb2NhdGlvbiIsIGNvbG5hbWVzKHRyYWluLmRhdGEpKQoKIyB0cmFpbi5kYXRhWyxwcmVkaWN0b3JzXQpmcmFtZSA8LSBkYXRhLmZyYW1lKHRyYWluLmRhdGFbLHByZWRpY3RvcnNdKQpmcmFtZQpvdXQuZmFjdG9yIDwtIHRyYWluLmRhdGEkSHVuZHJlZC5CbG9jay5Mb2NhdGlvbgphcy52ZWN0b3Iob3V0LmZhY3RvcikKCgpjb250cm9sIDwtIHJmZUNvbnRyb2woZnVuY3Rpb25zID0gcmZGdW5jcywgbWV0aG9kPSJjdiIsIG51bWJlcj0xMCkKcmVzdWx0cyA8LSByZmUoZnJhbWUsIG91dC5mYWN0b3IsIHNpemVzID0gYygxOjEzKSwgcmZlQ29udHJvbCA9IGNvbnRyb2wpICMgdGhpcyB3aWxsIHRha2UgQVdISUxFLi4uCgpyZXN1bHRzCmdncGxvdChyZXN1bHRzKQoKIyBjaG9zZW4gZmVhdHVyZXMKcHJlZGljdG9ycyhyZXN1bHRzKQpgYGAK